/*
 * JOGRE (Java Online Gaming Real-time Engine) - Server
 * Copyright (C) 2004  Bob Marks (marksie531@yahoo.com)
 * http://jogre.sourceforge.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.jogre.mayi.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import nanoxml.XMLElement;

import org.jogre.common.IGameOver;
import org.jogre.common.JogreModel;
import org.jogre.common.games.Card;
import org.jogre.common.games.Deck;
import org.jogre.common.util.JogreLogger;
import org.jogre.mayi.common.CommMayIHandScore;

/**
 * The spades server controller has several table variables that it needs to
 * keep track of. This spades table model is a convenient way to hold all
 * variables for a specific table. This model includes the hands of all players
 * with the deck is dealt. Keeping track of the current round's played cards.
 * Keeping track of what round it is. Keeping track of how many bids and bags,
 * etc.
 *
 * @author Garrett Lehman (Gman)
 * @version Alpha 0.2.3
 */
public class MayIServerTableModel extends JogreModel {

	// constant for game over
	private static final int GAME_OVER_POINTS = 500;

	// one round of hands delt to players
	private Deck[] hands = null;
	
	private Deck deck = null;

	// current round of cards on table
	private Card[] cards = null;

	// true or false if the player has requested their hand
	private boolean[] requestedHands = null;

	// round that have been played
	private int round = 0;

	private int dealerSeat = 0;
	
	private int players = -1;
	
	private Map<String, Integer> scorecard = new HashMap<String, Integer>();
	private List<CommMayIHandScore> newScores = new ArrayList<CommMayIHandScore>();
	
	private int currentMayISeat = -1;

	// logger for debugging purposes
	private JogreLogger logger = new JogreLogger(this.getClass());

	/**
	 * Contructor that requires table number. Each spades table should contain
	 * one of these server objects in order to keep all variables in server
	 * memory.
	 */
	public MayIServerTableModel(int numPlayers) {
		this.players = numPlayers;
		this.reset();
	}

	/**
	 * Reset all variables.
	 */
	public void reset() {
		this.round = 0;
		this.resetRound();
		this.dealerSeat = 0;
	}

	/**
	 * Reset variables when round is over.
	 */
	public void resetRound() {
		this.hands = new Deck[players];
		this.requestedHands = new boolean[players];

		dealHands();
	}


	/**
	 * Deal hands for all players.
	 */
	public synchronized void dealHands() {		
		Deck deck = new Deck();
		deck.loadStandardDeck();
		deck.loadStandardDeck();
		deck.shuffle();
		deck.shuffle();
		deck.shuffle();
		deck.shuffle();
		deck.shuffle();
		
		for (int i = 0; i < deck.size(); i++) {
			deck.get(i).setFaceUp(false);
		}

		for (int h = 0; h < players; h++) {
			hands[h] = new Deck();
		}
		
		int numCards = MayIConstants.ROUND_STRUCTURE[this.round][0];

		for (int c = 0; c < numCards; c++) {
			for (int h = 0; h < this.players; h++) {
				hands[h].addCard(deck.deal());
			}
		}
		
		this.deck = deck;

	}

	/**
	 * Request a specific player's hand.
	 *
	 * @param index
	 *            Seat number
	 * @return a players hand of cards
	 */
	public Deck requestHand(int seatNum) {
		this.requestedHands[seatNum] = true;
		return this.hands[seatNum];
	}
	
	public List<Deck> getHandsOrderedBySeat(int seatNum) {
		List<Deck> hands = new ArrayList<Deck>();
		for (int i = 0; i < players; i++) {
			Deck d = requestHand(seatNum);
			hands.add(d);
			seatNum = (seatNum + 1)%players;
		}
		return hands;
	}
	
	public Deck requestDeck() {
		return this.deck;
	}

	/**
	 * Sets the next round of play by incrementing the number of rounds and
	 * reseting all current round variables.
	 */
	public void nextRound() {
		this.round++;
		resetRound();
	}

	/**
	 * Get current round number
	 *
	 * @return current round number
	 */
	public int getRound() {
		return this.round;
	}
	
	public String getWinner() {
		int best = Integer.MAX_VALUE;
		String bestUser = null;
		for (String user : scorecard.keySet()) {
			if (scorecard.get(user) < best) {
				best = scorecard.get(user);
				bestUser = user;
			}
		}
		
		return bestUser;
	}

	/**
	 * Gets the score and bags for the specified team number.
	 *
	 * @param team Team number
	 * @return the score and bags for the specified team number
	 */
	public int getScore(int seat) {
		return 1;
	}

	public XMLElement flatten() {
		// FIXME FILL IN
		return null;
	}

	public void setState(XMLElement message) {
		// FIXME FILL IN
	}

	public Map<String, Integer> getScorecard() {
		return scorecard;
	}

	public List<CommMayIHandScore> getNewScores() {
		return newScores;
	}
	
	public void addNewScore(CommMayIHandScore score) {
		this.newScores.add(score);
	}
	
	public void clearNewScores() {
		this.newScores.clear();
	}
	
	public void addScore(String username, int score) {
		Integer oldScore = this.scorecard.get(username);
		this.scorecard.put(username, (oldScore+score));
	}
	
	public boolean allScoresReceived() {
		return (this.newScores.size() == this.players);
	}

	public int getCurrentMayISeat() {
		return currentMayISeat;
	}

	public void setCurrentMayISeat(int currentMayISeat) {
		this.currentMayISeat = currentMayISeat;
	}
	
	

}